#!python

# vPresent is an immersive presentation creation and display application.
# Copyright (C) 2007-2009 by Priority 5 Holdings, Inc.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

import os
import os.path
import re
import sys

import SCons

try:
   import SConsAddons
except:
   sys.path.append('deps/scons-addons/src')

import SConsAddons.Options as sca_opts
import SConsAddons.Options.Boost as Boost
import SConsAddons.Options.OpenSG2 as OpenSG2
import SConsAddons.Util as sca_util
import SConsAddons.EnvironmentBuilder as eb
import SConsAddons.Builders as builders


license = \
'''# vPresent is an immersive presentation creation and display application.
# Copyright (C) 2007-2009 by Priority 5 Holdings, Inc.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

'''

# This helper function removes the "Created:/by:" comments from the generated
# Python source. These comments are included by the PyQt code generation
# tools, and they pose a problem for SCons. The first time that someone checks
# out the source and runs SCons, the PyQt code generation tools will be run
# because SCons does know that doing so is unnecessary. The result is that the
# generated code will be the same *except* for the "Created:/by:" comments.
# By stripping out those comments, we can be sure that regenerating the code
# unnecessarily will not cause unwanted modifications to occur to checked in
# source.
def stripCreationInfo(source):
   if os.path.exists(source):
      creation_re = re.compile(r'^# (?:Created:|Form implementation) (.+)$')

      f = open(source, 'r')
      lines = f.readlines()
      f.close()

      f = open(source, 'w+')

      line_count = len(lines)
      i = 0
      while i < line_count:
         l = lines[i]
         match = creation_re.search(l)
         if match is not None:
            # Skip the "Created:" line, the "by:" line, and the blank line
            # after.
            i = i + 3
         else:
            f.write(l)
            i = i + 1

      f.close()

def addLicense(source):
   if os.path.exists(source):
      f = open(source, 'r')
      lines = f.readlines()
      f.close()

      f = open(source, 'w+')
      f.write(license)

      for l in lines:
         f.write(l)

      f.close()

def runPyrcc(target = None, source = None, env = None):
   qrc_file = str(source[0])
   py_file  = str(target[0])
   pyrcc_build_str = 'pyrcc4 -compress 5 %s -o %s' % (qrc_file, py_file)
   status = env.Execute(pyrcc_build_str)

   if status == 0:
      stripCreationInfo(py_file)
      addLicense(py_file)

   return status

def registerPyrccBuilder(env):
   # Translate filename.qrc to filename_rc.py. For whatever reason, pyuic4
   # adds an 'import filename_rc' line (rather than 'import filename' for each
   # referenced .qrc file. Therefore, we have to be sure to generate a Python
   # file with the correct name so that no post processing of files genertec
   # by pyuic4 is needed.
   def qrcEmitter(target, source, env):
      for i in range(len(source)):
         target[i] = os.path.splitext(str(source[i]))[0] + '_rc.py'
      return (target, source)

   # Extract implicit dependencies from .qrc files.
   def qrcScanner(node, env, path):
      qrc_file = str(node)
      deps = []

      if os.path.exists(qrc_file):
         file_re = re.compile('<file>(.*?)</file>')

         f = open(qrc_file, 'r')
         contents = f.read()
         f.close()

         base_dir = os.path.split(qrc_file)[0]
         files = file_re.findall(contents)
         for f in files:
            dep_file = os.path.join(base_dir, f)

            # Here, we test to see if f exists relative to base_dir. This is
            # needed to contend with the current working directory for scons.
            # If f does exist, then we add it to deps without base_dir
            # prepdended, once again to deal with scons behavior.
            if os.path.exists(dep_file):
               deps.append(f)
            
      return deps

   pyrcc_builder = Builder(action = Action(runPyrcc), src_suffix = '.qrc',
                           suffix = '.py', emitter = qrcEmitter,
                           source_scanner = Scanner(function = qrcScanner))

   env.Append(BUILDERS = {'Pyrcc' : pyrcc_builder})

def installDataFiles(env, rootDir, destDir):
   pj = os.path.join

   def doInstall(junk, dirPath, files):
      if dirPath.count('.svn') == 0:
         if rootDir == dirPath:
            inst_subdir = destDir
         else:
            inst_subdir = pj(destDir, dirPath.replace(rootDir + os.sep, ''))

         for n in files:
            full_file_name = os.path.join(dirPath, n)
            if os.path.isfile(full_file_name):
               env.Install(inst_subdir, full_file_name)

   os.path.walk(rootDir, doInstall, None)

GetPlatform = sca_util.GetPlatform
Export('GetPlatform', 'stripCreationInfo', 'addLicense')

platform = GetPlatform()
options_filename = 'config.cache.' + platform

EnsureSConsVersion(0, 96)
SetOption('implicit_cache', 1)
SConsignFile('.sconsign.' + platform)

if platform == 'win32':
   common_env = Environment(ENV = os.environ)
else:
   common_env = Environment(ENV = os.environ)
   common_env.Append(CXXFLAGS = ['-g'])

builders.registerSubstBuilder(common_env)
common_env["CONFIGUREDIR"] = '.sconf_temp_' + platform
common_env["CONFIGURELOG"] = 'sconf.log_' + platform

registerPyrccBuilder(common_env)

opts = sca_opts.Options(files = [options_filename, 'options.custom'],
                        args = ARGUMENTS)
use_boost_version = platform == 'win32' or platform == 'darwin'
boost_options = Boost.Boost('boost', '1.32', useMt = True,
                            useVersion = use_boost_version,
                            preferDynamic = True, autoLink = True,
                            libs = ['filesystem', 'signals', 'program_options'],
                            required = True)

opensg_options = OpenSG2.OpenSG2('opensg', '2.0', required = True)
opts.Add('prefix', 'Installation prefix', '/usr/local')
opts.AddOption(sca_opts.SeparatorOption('\nPackage Options'))
opts.AddOption(boost_options)
opts.AddOption(opensg_options)

base_builder = eb.EnvironmentBuilder()
base_builder.addOptions(opts)

Export('opts', 'common_env', 'boost_options', 'opensg_options')

help_text = '''
vPresent Build
%s

Targets:
   install: Install vPresent
''' % opts.GenerateHelpText(common_env)

if not sca_util.hasHelpFlag():
   opts.Process(common_env)
   try:
      opts.Save(options_filename, common_env)
   except LookupError, le:
      pass

   base_builder.readOptions(common_env)

   # This has to happen after reading the options so that we get default
   # settings.
   base_builder.enableWarnings()

   prefix = common_env['prefix']
   base_paths = {
      'prefix'   : prefix,
      'bin'      : os.path.join(prefix, 'bin'),
      'confdir'  : '/etc',
      'lib'      : os.path.join(prefix, 'lib'),
      'sbin'     : os.path.join(prefix, 'sbin'),
      'share'    : os.path.join(prefix, 'share', 'vpresent'),
   }

   base_paths['vpresent'] = os.path.join(base_paths['lib'], 'vpresent')
   base_paths['gui']      = os.path.join(base_paths['vpresent'], 'gui')
   base_paths['opendoc']  = os.path.join(base_paths['vpresent'],
                                         'opendocument')

   Export('base_paths')
   common_env.Alias('install', base_paths['prefix'])

   qrc_src_files = []
   for path, dirs, files in sca_util.WalkBuildFromSource('.', common_env):
      qrc_src_files += \
         [os.path.join(path, f) for f in files if f.endswith('.qrc')]

   for f in qrc_src_files:
      common_env.Pyrcc(f)

   SConscript(dirs = ['gui', 'server'])

   submap = {
      '@lib@'     : base_paths['lib'],
      '@confdir@' : base_paths['confdir']
   }

   vpresent_run = common_env.SubstBuilder('scripts/vpresent',
                                          'scripts/vpresent.in',
                                          submap = submap)
   common_env.AddPostAction(vpresent_run, Chmod('$TARGET', 0755))

   common_env.Install(base_paths['share'], ['LICENSE.txt'])
   common_env.Install(base_paths['share'], ['LICENSE.html'])

   # Install the vPresent GUI Python code.
   common_env.Install(base_paths['vpresent'],
                      ['vpresent.py', 'vpresent_rc.py', 'LICENSE.html'])
   installDataFiles(common_env, common_env.Dir('data').srcnode().abspath,
                    os.path.join(base_paths['vpresent'], 'data'))
   installDataFiles(common_env, common_env.Dir('gui').srcnode().abspath,
                    base_paths['gui'])
   installDataFiles(common_env,
                    common_env.Dir('opendocument').srcnode().abspath,
                    base_paths['opendoc'])

   # Install the script that actually runs the vPresent GUI.
   common_env.Install(base_paths['bin'], vpresent_run)

Default('.')

Help(help_text)
